using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web.Mvc;
using Complaint.ActionResults;
using Complaint.Common;
using Complaint.Models;
using Complaint.Models.Dtos;
using Complaint.Models.Dtos.Enums;
using MvcContrib.Pagination;

namespace Complaint.Controllers
{
    [HandleError]
    public class ComplaintController : BaseController
    {
        //
        // GET: /Complaint/
        public ActionResult Index(int? page)
        {
            using (new UnitOfWorkScope(false))
            {
                var model = new ComplaintModel();
                int totalCount;
                var complaints =
                    model.Retrieve(LoadComplaint.Organisation | LoadComplaint.User, page ?? 1, PageSize, out totalCount).AsEnumerable();

                complaints = new CustomPagination<Models.Dtos.Complaint>(complaints, page ?? 1, PageSize, totalCount);

                if (!Request.IsAjaxRequest())
                    return View(complaints);

                return PartialView("Grid", complaints);
            }
        }

        //
        // GET: /Complaint/SearchByUser/username
        [Authorize]
        public ActionResult SearchByUser(string userName, int? page)
        {
            using (new UnitOfWorkScope(false))
            {
                var model = new ComplaintModel();
                var userModel = new UserModel();
                var user = userModel.FindByName(userName).FirstOrDefault();
                int totalCount;
                var complaints = model.FindByUser(
                                    user.UserID,
                                    LoadComplaint.Organisation | LoadComplaint.User | LoadComplaint.Settlement,
                                    page ?? 1,
                                    PageSize,
                                    out totalCount).AsEnumerable();

                complaints = new CustomPagination<Models.Dtos.Complaint>(complaints, page ?? 1, PageSize, totalCount);

                if (HttpContext.User.Identity.Name != user.Email)
                    return View("InvalidOperation");

                if (!Request.IsAjaxRequest())
                    return View("Index", complaints);

                return PartialView("Grid", complaints);
            }
        }

        //
        // POST: /Complaint/Search
        public ActionResult Search(string keywords, int? page)
        {
            using (new UnitOfWorkScope(false))
            {
                var model = new ComplaintModel();
                int totalCount;
                var complaints = String.IsNullOrEmpty(keywords)
                                     ? model.Retrieve(LoadComplaint.Organisation | LoadComplaint.User, page ?? 1,
                                                      PageSize, out totalCount).AsEnumerable()
                                     : model.FindByKeywords(keywords, LoadComplaint.Organisation | LoadComplaint.User,
                                                            page ?? 1, PageSize, out totalCount).AsEnumerable();

                complaints = new CustomPagination<Models.Dtos.Complaint>(complaints, page ?? 1, PageSize, totalCount);
                ViewData["Keywords"] = keywords;

                return PartialView("Grid", complaints);
            }
        }

        //
        // GET: /Complaint/SearchByOrganisation/2
        public ActionResult SearchByOrganisation(int id, int? page)
        {
            using (new UnitOfWorkScope(false))
            {
                var model = new ComplaintModel();
                int totalCount;
                var complaints =
                    model.FindByOrganisation(id, LoadComplaint.Organisation | LoadComplaint.User, page ?? 1, PageSize, out totalCount).AsEnumerable();

                complaints = new CustomPagination<Models.Dtos.Complaint>(complaints, page ?? 1, PageSize, totalCount);

                if (!Request.IsAjaxRequest())
                    return View("Index", complaints);

                return PartialView("Grid", complaints);

            }
        }

        //
        // GET: /Complaint/SearchByCategory/2
        public ActionResult SearchByCategory(int id, int? page)
        {
            using (new UnitOfWorkScope(false))
            {
                var model = new ComplaintModel();
                int totalCount;
                var complaints =
                    model.Retrieve(LoadComplaint.Organisation | LoadComplaint.User, page ?? 1,
                                   PageSize, out totalCount, id).AsEnumerable();

                complaints = new CustomPagination<Models.Dtos.Complaint>(complaints, page ?? 1, PageSize, totalCount);

                if (!Request.IsAjaxRequest())
                    return View("Index", complaints);

                return PartialView("Grid", complaints);
            }
        }

        //
        // GET: /Complaint/Details/5
        public ActionResult Details(int id)
        {
            using (new UnitOfWorkScope(false))
            {
                var model = new ComplaintModel();
                var complaint =
                    model.FindById(id, LoadComplaint.User | LoadComplaint.Organisation | LoadComplaint.Settlement);
                var commentModel = new CommentModel();
                var comments = commentModel.FindByComplaintId(id);
                ViewData["Comments"] = comments;

                try
                {
                    ViewData["ListURL"] = Request.UrlReferrer;
                }
                catch (NullReferenceException)
                {
                    var u = new UrlHelper(ControllerContext.RequestContext);
                    ViewData["ListURL"] = u.Action("Index");
                }

                return View(complaint);
            }
        }

        public CaptchaActionResult Captcha()
        {
            var random = Utility.GetRandomWord(ConfigHelper.GetConfigValueAsInt("CaptchaWordLength"));
            Session["CAPTCHA_CODE"] = random;
            return new CaptchaActionResult { RandomWord = random };
        }

        public ActionResult DisplayImage(string path)
        {
            var image = new FileInfo(path);
            return File(image.FullName, Utility.GetMimeType(image.FullName));
        }

        //
        // GET: /Complaint/AddComment
        public ActionResult AddComment(int id)
        {
            var comment = new Comment();
            ViewData["ComplaintID"] = id;
            return PartialView(comment);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult AddComment(int id, Comment comment)
        {
            var code = Request.Form["CaptchaCode"];
            if (String.IsNullOrEmpty(code)
                || !String.Equals(code, Session["CAPTCHA_CODE"].ToString(), StringComparison.CurrentCulture))
            {
                ModelState.AddModelError("CaptchaCode", "Verification code does not match.");
                // if Builtin Model Binding is not used, for every ModelError added, a ModelValue is also needed 
                if (ModelState["CaptchaCode"].Value == null)
                {
                    ModelState["CaptchaCode"].Value =
                        new ValueProviderResult(
                            code,
                            code,
                            CultureInfo.CurrentCulture);
                }
                Response.StatusCode = 500;
                return PartialView(comment);
            }

            try
            {
                using (new UnitOfWorkScope(true))
                {
                    var model = new CommentModel();
                    var cm = new ComplaintModel();
                    var complaint = cm.FindById(id);
                    comment.Complaint = complaint;
                    comment.IP = Request.UserHostAddress;
                    model.Create(comment);
                    var comments = model.FindByComplaintId(id);
                    return PartialView("CommentGrid", comments);
                }
            }
            catch (ComplaintDataException e)
            {
                foreach (var error in e.DataValidationErrors)
                {
                    ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
                }
                Response.StatusCode = 500;
                return PartialView(comment);
            }
        }

        public ActionResult ReportComment(int id)
        {
            try
            {
                using (new UnitOfWorkScope(false))
                {
                    var model = new CommentModel();
                    model.Report(
                        id, 
                        ConfigHelper.GetConfigValue("CommentReporter"),
                        ConfigHelper.GetConfigValue("CommentModerator"));
                }
                return Content("We have received your report, thank you.");
            }
            catch (Exception)
            {
                return Content("Oops, there is a technical problem ocurred, sorry for any inconvenience.");
            }
        }
        //
        // GET: /Complaint/Create
        [Authorize]
        public ActionResult Create(int id)
        {
            using (new UnitOfWorkScope(false))
            {
                var model = new OrganisationModel();
                var organisation = model.FindById(id);

                ViewData["Organisation"] = organisation;
            }
            return View();
        }

        //
        // POST: /Complaint/Create
        [AcceptVerbs(HttpVerbs.Post), Authorize]
        public ActionResult Create(int id, Models.Dtos.Complaint complaint)
        {
            try
            {
                complaint.Proof = FileUploader.SaveProofFile(Request.Files);

                using (new UnitOfWorkScope(false))
                {
                    var model = new ComplaintModel();

                    var um = new UserModel();
                    var user = um.FindByName(HttpContext.User.Identity.Name).FirstOrDefault();
                    complaint.User = user;

                    var om = new OrganisationModel();
                    var org = om.FindById(id);
                    ViewData["Organisation"] = org;
                    complaint.Organisation = org;

                    model.Create(complaint, ConfigHelper.GetConfigValue("CommentReporter"));
                    ViewData["Action"] = "created";
                    return View("Confirmation", complaint);
                }
            }
            catch (ComplaintDataException e)
            {
                ModelState.Clear();
                foreach (var error in e.DataValidationErrors)
                {
                    ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
                }

                return View(complaint);
            }
            catch (ArgumentOutOfRangeException ae)
            {
                using (new UnitOfWorkScope(false))
                {
                    var om = new OrganisationModel();
                    var org = om.FindById(id);
                    ViewData["Organisation"] = org;
                }
                ModelState.AddModelError("Proof", ae.Message);
                return View(complaint);
            }
            catch (InvalidOperationException ie)
            {
                using (new UnitOfWorkScope(false))
                {
                    var om = new OrganisationModel();
                    var org = om.FindById(id);
                    ViewData["Organisation"] = org;
                }
                ModelState.AddModelError("Proof", ie.Message);
                return View(complaint);
            }
        }

        //
        // GET: /Complaint/Edit/5
        [Authorize]
        public ActionResult Edit(int id)
        {
            using (new UnitOfWorkScope(false))
            {
                var model = new ComplaintModel();
                var complaint = model.FindById(id, LoadComplaint.User | LoadComplaint.Organisation | LoadComplaint.Settlement);

                if (complaint.Settlement.Count > 0)
                    return View("InvalidOperation");

                return !complaint.IsLodgedBy(HttpContext.User.Identity.Name) ? View("InvalidOperation") : View(complaint);
            }
        }

        //
        // POST: /Complaint/Edit/5

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Edit(int id, FormCollection collection)
        {
            try
            {
                using (new UnitOfWorkScope(false))
                {
                    var model = new ComplaintModel();
                    var complaint = model.FindById(id, LoadComplaint.Organisation | LoadComplaint.User);
                    complaint.AgreedToTnc = true;
                    UpdateModel(complaint);
                    complaint.Proof = FileUploader.SaveProofFile(Request.Files);
                    complaint.DateModified = DateTime.Now;

                    model.Update(complaint);
                    return RedirectToAction("Index");
                }
            }
            catch (ComplaintDataException e)
            {
                foreach (var error in e.DataValidationErrors)
                {
                    ModelState.AddModelError(error.PropertyName ?? "", error.ErrorMessage);
                }
                return DisplayError(id);
            }
            catch (ArgumentOutOfRangeException ae)
            {
                //ModelState.AddModelError("Proof", ae.Message);
                return DisplayError(id);
            }
            catch(InvalidOperationException ie)
            {
                //ModelState.AddModelError("Proof", ie.Message);
                return DisplayError(id);
            }
        }

        private ActionResult DisplayError(int id)
        {
            using (new UnitOfWorkScope(false))
            {
                var model = new ComplaintModel();
                var complaint = model.FindById(id, LoadComplaint.Organisation | LoadComplaint.User);
                return View(complaint);
            }
        }

        //
        // GET: /Complaint/Settle/5
        [Authorize]
        public ActionResult Settle(int id)
        {
            using (new UnitOfWorkScope(false))
            {
                var model = new ComplaintModel();
                var complaint = model.FindById(id, LoadComplaint.User);
                ViewData["Complaint"] = complaint;

                var sm = new SettlementTypeModel();
                var types = sm.Retrieve();
                ViewData["SettlementTypes"] = types;

                if (!complaint.IsLodgedBy(HttpContext.User.Identity.Name) || complaint.IsSettled)
                    return View("InvalidOperation");

                return View();
            }
        }

        //
        // GET: /Complaint/Delete/5
        [Authorize]
        public ActionResult Delete(int id)
        {
            using (new UnitOfWorkScope(false))
            {
                var model = new ComplaintModel();
                var complaint = model.FindById(id, LoadComplaint.User);
                ViewData["Complaint"] = complaint;
                ViewData["User"] = complaint.User.DisplayName;

                if (!complaint.IsLodgedBy(HttpContext.User.Identity.Name) || complaint.IsSettled)
                    return View("InvalidOperation");

                model.Delete(complaint);
                ViewData["Action"] = "deleted";
                return View("Confirmation", ViewData["Complaint"]);
            }
        }

        //
        // POST: /Complaint/Settle/5
        [AcceptVerbs(HttpVerbs.Post), Authorize]
        public ActionResult Settle(int id, Settlement settlement)
        {
            try
            {
                using (new UnitOfWorkScope(false))
                {
                    var model = new SettlementModel();
                    var cm = new ComplaintModel();
                    var complaint = cm.FindById(id, LoadComplaint.User);
                    ViewData["Complaint"] = complaint;

                    var stm = new SettlementTypeModel();
                    int stId;
                    int.TryParse(Request.Form["SettlementTypeID"], out stId);
                    var settlementType = stm.FindById(stId);

                    settlement.Complaint = complaint;
                    settlement.SettlementType = settlementType;
                    model.Create(settlement);

                    return View("Settled", complaint);
                }
            }
            catch (ComplaintDataException e)
            {
                foreach (var error in e.DataValidationErrors)
                {
                    ModelState.AddModelError(error.PropertyName ?? "", error.ErrorMessage);
                }
                using (new UnitOfWorkScope(false))
                {
                    var sm = new SettlementTypeModel();
                    var types = sm.Retrieve();
                    ViewData["SettlementTypes"] = types;

                    return View();
                }
            }

        }
    }
}
